package com.heima.wemedia.service.impl;

import apis.article.IArticleClient;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.verify.service.impl.VerifyMaterialServiceImpl;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private VerifyMaterialServiceImpl verifyMaterialService;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient iArticleClient;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CacheService cacheService;

    /**
     * 文章审核功能
     * 审核流程：
     * 1.校验数据（有内容、状态为待审核）
     * 2.开始审核（抽取内容和图片）
     *
     * @param id
     */
    @Override
//    @Async
    public void autoScanWmNews(Integer id) {
        //1.校验数据
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null || StringUtils.isEmpty(wmNews.getContent())) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (wmNews.getStatus() == WmNews.Status.NORMAL.getCode()) {
            return;
        }

        //2.抽取内容文本和图片
        Map<String, Object> map = handTextAndImage(wmNews);

        //3.校验文本内容
        //3.1 自定义铭感词校验
        boolean isSensitive = handleSensitiveScan((String) map.get(WemediaConstants.WM_LIST_TEXT), wmNews);
        if (!isSensitive) return;
        //3.2 百度云校验
        boolean textBoolean = verifyText((String) map.get(WemediaConstants.WM_LIST_TEXT), wmNews);
        if (!textBoolean) return;

        //4.校验图片内容
        boolean imageBoolean = verifyImage((List<String>) map.get(WemediaConstants.WM_LIST_IMAGE), wmNews);
        if (!imageBoolean) return;

        //5.远程调用保存
        publishNews(wmNews);
    }


    public void publishNews(WmNews wmNews) {
        try {
            ResponseResult<Long> responseResult = saveOrUpdate(wmNews);
            if (responseResult.getCode() == 200) {
                wmNews.setArticleId(responseResult.getData());
                updateRes(WmNews.Status.PUBLISHED.getCode(), "全部通过审核", wmNews);
            } else {
                updateRes(WmNews.Status.SUCCESS.getCode(), "审核成功,发布失败", wmNews);
            }
        } catch (Exception e) {
            updateRes(WmNews.Status.SUCCESS.getCode(), "审核成功,发布失败", wmNews);
        }
    }

    private boolean handleSensitiveScan(String text, WmNews wmNews) {
        boolean flag = true;
        if (StringUtils.isNotEmpty(text)) {
            //查询敏感词库
            String context = cacheService.get(WemediaConstants.WM_SENSITIVE);
            List contextList = JSON.parseObject(context, List.class);
            if (contextList == null) {
                List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
                contextList = wmSensitives.stream().map(wmSensitive -> wmSensitive.getSensitives()).collect(Collectors.toList());
                cacheService.set(WemediaConstants.WM_SENSITIVE,JSON.toJSONString(contextList));
            }
            //初始化
            SensitiveWordUtil.initMap(contextList);
            Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
            if (map.size() > 0) {
                flag = false;
                Set<String> keySet = map.keySet();
                String reason = "审核失败：" + keySet;
                updateRes(WmNews.Status.FAIL.getCode(), reason, wmNews);
            }
        }
        return flag;
    }

    /**
     * 自定义铭感词校验
     * @param text
     * @param wmNews
     * @return
     */
    private boolean handleSensitiveScan1(String text, WmNews wmNews) {
        boolean flag = true;
        List sensitiveList = (List) redisTemplate.opsForValue().get("sensitive");
        if (sensitiveList == null) {
            List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
            sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            redisTemplate.opsForValue().set("sensitive", sensitiveList);
        }
        SensitiveWordUtil.initMap(sensitiveList);
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        if (map.size() > 0) {
            flag = false;
            Set<String> strings = map.keySet();
            String reason = "审核失败：" + strings;
            updateRes(WmNews.Status.FAIL.getCode(), reason, wmNews);
        }
        return flag;
    }



    /**
     * 保存
     * @param wmNews
     */
    private ResponseResult<Long> saveOrUpdate(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        //1.处理作者
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            articleDto.setAuthorName(wmUser.getName());
            articleDto.setAuthorId(wmNews.getUserId().longValue());
        }
        //2.处理布局
        articleDto.setLayout(wmNews.getType());
        //3.处理channel
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null) {
            articleDto.setChannelName(wmChannel.getName());
        }
        //4.处理作品ID
        if (wmNews.getArticleId() != null) {
            articleDto.setId(wmNews.getArticleId());
        }
        return iArticleClient.saveOrUpdateArticle(articleDto);
    }

    /**
     * 图片检测
     * @param imageList
     * @param wmNews
     * @return
     */
    private boolean verifyImage(List<String> imageList, WmNews wmNews) {
        boolean flag = true;
        if (imageList != null && imageList.size() > 0) {
            try {
                for (String image : imageList) {
                    Map res = verifyMaterialService.VerifyImage(fileStorageService.downLoadFile(image));
                    Integer type = (Integer) res.get("conclusionType");
                    if (type == WemediaConstants.WM_CHECK_FORBID) {
                        flag = false;
                        updateRes(WmNews.Status.ADMIN_AUTH.getCode(), "需要人工进一步审核", wmNews);
                        break;
                    } else if (type==WemediaConstants.WM_CHECK_MAYBE || type==WemediaConstants.WM_CHECK_UNKNOWN){
                        flag = false;
                        updateRes(WmNews.Status.FAIL.getCode(), "审核失败，文章素材存在敏感地方", wmNews);
                        break;
                    }
                }
            } catch (Exception e) {
                flag = false;
                updateRes(WmNews.Status.FAIL.getCode(), "审核失败，文章素材存在敏感地方", wmNews);
            }
        }
        return flag;
    }

    /**
     * 校验文本
     * @param text
     * @param wmNews
     * @return
     */
    private boolean verifyText(String text, WmNews wmNews) {
        boolean flag = true;
        if (StringUtils.isNotEmpty(text)) {
            try {
                Map res = verifyMaterialService.VerifyText(text);
                Integer type = (Integer) res.get("conclusionType");
                if (type == WemediaConstants.WM_CHECK_MAYBE || type == WemediaConstants.WM_CHECK_UNKNOWN) {
                    flag = false;
                    updateRes(WmNews.Status.ADMIN_AUTH.getCode(), "需要人工进一步审核", wmNews);
                } else if (type == WemediaConstants.WM_CHECK_FORBID) {
                    flag = false;
                    updateRes(WmNews.Status.FAIL.getCode(), "审核失败，文章内容存在敏感地方", wmNews);
                }
            } catch (Exception e) {
                flag = false;
                updateRes(WmNews.Status.FAIL.getCode(), "审核失败，文章内容存在敏感地方", wmNews);
            }
        }
        return flag;
    }

    private void updateRes(Short type, String reason, WmNews wmNews) {
        wmNews.setReason(reason);
        wmNews.setStatus(type);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 抽取内容文本和图片+图片文字信息
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handTextAndImage(WmNews wmNews) {
        StringBuilder text = new StringBuilder(wmNews.getTitle());
        text.append(",").append(wmNews.getLabels()).append(",");
        List<String> imageList = new ArrayList<>();
        List<Map> maps = JSON.parseArray(wmNews.getContent(), Map.class);
        for (Map<String, String> map : maps) {
            if (map.get("type").equals("text")) {
                text.append(map.get("value"));
            }
            if (map.get("type").equals("image")) {
                imageList.add(map.get("value"));
            }
        }
        if (StringUtils.isNotEmpty(wmNews.getImages())) {
            imageList.addAll(Arrays.asList(wmNews.getImages().split(",")));
        }
        //剔除重复素材
        imageList = imageList.stream().distinct().collect(Collectors.toList());
        //提取图片中的文字消息
        if (imageList.size() > 0) {
            try {
                for (String image : imageList) {
                    byte[] bytes = fileStorageService.downLoadFile(image);
                    ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
                    BufferedImage in = ImageIO.read(inputStream);
                    String res = tess4jClient.doOCR(in);
                    text.append(",").append(res);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


//        try {
//            if (imageList.size() > 0) {
//                for (String image : imageList) {
//                    byte[] bytes = fileStorageService.downLoadFile(image);
//                    ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
//                    BufferedImage in = ImageIO.read(inputStream);
//                    String imageText = tess4jClient.doOCR(in);
//                    text.append(",").append(imageText);
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        //封装数据
        Map<String, Object> map = new HashMap<>();
        map.put("text", text.toString());
        map.put("image", imageList);
        return map;
    }


}
